'use strict';
import download from 'download';
import { JSONFilePreset } from 'lowdb/node';
import puppeteer from 'puppeteer';
import { existsSync } from 'node:fs';

let jdb;

// 获取总页数
async function getTotalPage() {
    const url = 'https://www.oreilly.com/animals.csp';
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    await page.setViewport({ width: 1080, height: 1024 });

    const res = await page.evaluate(async () => {
        await new Promise((r) => setTimeout(r, 3000));
        let elems = document.querySelectorAll('.cs-prevnext');
        let totalPage = 0;
        const ptn = new RegExp('\\d+ +to +\\d+ +of +(\\d+)');
        for (let i = 0; i < elems.length; i++) {
            const s = elems[i].innerText;
            const matched = s.match(ptn);
            if (matched) {
                totalPage = Math.ceil(matched[1] / 20);
                break;
            }
        }
        return totalPage;
    });

    await browser.close();
    return res;
}

// 获取指定页的数据
async function getLinksPage(index) {
    let url = 'https://www.oreilly.com/animals.csp';
    if (index > 0) {
        url += '?x-o=' + (index * 20);
    }

    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    await page.setViewport({ width: 1080, height: 1024 });

    const res = await page.evaluate(async () => {
        await new Promise((r) => setTimeout(r, 3000));
        let elems = document.querySelectorAll('.animal-row');
        const links = [];
        const ptn = RegExp('/\\d+w/');
        for (let i = 0; i < elems.length; i++) {
            const elm = elems[i];
            const cvrElm = elm.querySelector('.book-cvr');
            const data = {};
            if (cvrElm) {
                const cvrUrl = cvrElm.getAttribute('src');
                data.cover = cvrUrl.replace(ptn, '/1080w/');
                data.url = elm.querySelector('a.book').getAttribute('href');
                data.animalName = elm.querySelector('.animal-name').innerText;
                data.title = elm.querySelector('.book-title').innerText;
                links.push(data);
            }
        }
        return links;
    });

    await browser.close();
    return res;
}

// 参数处理
const args = process.argv;
const n = args.length;
let fromIndex = 0;
let downloadCover = false;
if (n >= 3) {
    fromIndex = parseInt(args[2], 10);
    if (n >= 4) {
        downloadCover = true;
    }
}

// 主流程
(async () => {
    jdb = await JSONFilePreset('oreillycover.json', { books: [] });

    console.log('@@@ start from ' + fromIndex);
    const totalPage = await getTotalPage();

    for (let i = fromIndex; i < totalPage; i++) {
        try {
            console.log('@@@ page =', i);
            const list = await getLinksPage(i);
            const ptn = new RegExp('/urn:orm:book:(.*?)/');
            for (const item of list) {
                const { cover, url, title, animalName } = item;
                if (typeof cover === 'string') {
                    let matched = cover.match(ptn);
                    if (matched) {
                        const sn = matched[1];

                        const dbBook = jdb.data.books.find((book) => book.sn === sn);
                        if (!dbBook) {
                            jdb.data.books.push({
                                sn,
                                title,
                                cover,
                                url,
                                animalName
                            });
                            await jdb.write();
                        }

                        if (downloadCover) {
                            const filename = `${sn}.jpg`;
                            const outputDir = '../images/oreilly_covers';
                            if (existsSync(`${outputDir}/${filename}`)) {
                                console.log('文件已存在');
                            } else {
                                await download(cover, outputDir, { filename });
                            }
                        }
                    }
                }
            }
        } catch (e) {
            console.error(e.message);
        }
    }
})();
